module MEM(clk, reset, icode, valA, valE, mem_data_i, mem_address, mem_data_o, mem_ub, mem_lb, mem_write, valM, WAIT);
input clk;
input reset;
input [3:0] icode;
input [31:0] valA;
input [31:0] valE;
input [15:0] mem_data_i;

output [31:0] mem_address;
output [15:0] mem_data_o;
output mem_ub;
output mem_lb;
output mem_write;
output [31:0] valM;
output WAIT;


wire counter;
wire [31:0] address;
wire [31:0] newAddress;
wire [31:0] readAddress;
wire [31:0] writeAddress;
wire [31:0] mem_read_addr;
wire [31:0] mem_write_addr;
wire readEnable;
wire writeEnable;
wire [47:0] readData;
wire [31:0] writeData;


assign mem_address = (writeEnable && !readEnable)? mem_write_addr: mem_read_addr;
assign mem_write = (writeEnable && !readEnable)? 1 : 0;
assign address = (icode == 9 || icode == 11)? valA : valE;
assign valM = {readData[23:16], readData[31:24], readData[39:32], readData[47:40]};

Counter2b cnt(
			.clk(clk), 
			.reset(WAIT), 
			.out(counter));

AddressIncrementer addrInc(
			.counter(counter), 
			.address(address), 
			.newAddress(newAddress));

MemReadWriteChooser chooser(
			.address(newAddress), 
			.icode(icode), 
			.readEnable(readEnable), 
			.writeEnable(writeEnable), 
			.readAddress(readAddress), 
			.writeAddress(writeAddress));

ReadMemory rmem(
			.address(readAddress), 
			.counter(counter), 
			.mem_addr(mem_read_addr), 
			.mem_data(mem_data_i), 
			.data(readData));
			
WriteMemory wmem(
			.address(writeAddress), 
			.counter(counter), 
			.data(writeData), 
			.mem_addr(mem_write_addr),
			.mem_data(mem_data_o));
			
MemWaitGenerator waitGen(
			.reset(reset), 
			.readEnable(readEnable), 
			.writeEnable(writeEnable), 
			.address(newAddress), 
			.counter(counter), 
			.WAIT(WAIT));

endmodule
